from marshmallow import Schema, fields, validate, ValidationError, pre_load
from enums.AppEnum import AppEnum
from models import App,ScoringResult
from common.BaseResponse import BaseResponse
from common.ApiResponse import ApiResponse
from common.ErrorCode import ErrorCode

# 预定义错误
param_error = BaseResponse.from_error_code(ErrorCode.PARAMS_ERROR)


class addScoringResult(Schema):
    id = fields.Int(
        required=False,
        allow_none=True,
        validate=validate.Range(min=1)
    )
    appId = fields.Int(
        allow_none=False,
        validate=validate.Range(min=1)
    )
    resultName = fields.Str(
        required=True,
        allow_none=False,
        validate=validate.Length(max=80, error="结果名称不得超过80个字符")
    )
    resultDesc = fields.Str(
        required=True,
        allow_none=True,
        validate=validate.Length(max=80, error="结果描述不得超过80个字符")
    )
    resultPicture = fields.Str(
        required=False,
        allow_none=True,
        # require_tld=True,  # 要求顶级域名（如 .com/.org）
        # relative=False,  # 禁止相对URL（如 /path/to/resource）
        # schemes={'http', 'https', 'ftp'}  # 允许的协议
    )
    resultProp = fields.List(
        required=True,
        allow_none=True,
        cls_or_instance=fields.String(),
        validate=validate.Length(min=1, error="选项数组至少需要包含一个元素")
    )
    resultScoreRange = fields.Int(
        required=True,
        allow_none=True,
    )

    def validate_appId(self,data,**kwargs):
        global appId
        try:
            appId = int(data.get('appId'))
        except ValueError as err:
            print(f"appId{appId}非法，应输入整数.{err}")
            return ApiResponse.error_from_baseResponse(
                baseResponse=param_error,
                data="appId非法，应输入整数！"
            )
        app = App.query.get(appId)
        if app is None:
            print(f"app不存在，校验失败")
            return ApiResponse.error_from_baseResponse(
                baseResponse=param_error,
                data="请重新检查选择的app"
            )

    def validate_resultProp(self, data, **kwargs):
        app = App.query.get(data.get('appId'))
        app_type = app.appType
        result_prop = data.get("resultProp")

        if app_type == AppEnum.Evaluation_Category.value and result_prop is None:
            print('当app类型为测评类时，resultProp必须填写！')
            return ApiResponse.error_from_baseResponse(baseResponse=param_error,data="当app类型为测评类时，resultProp必须填写！")

    def validate_resultScoreRange(self, data, **kwargs):
        app = App.query.get(data.get('appId'))
        app_type = app.appType
        result_score_range = data.get("resultScoreRange")

        if app_type == AppEnum.Scoring_Category.value and result_score_range is None:
            print('当app类型为得分类时，resultScoreRange必须填写！')
            return ApiResponse.error_from_baseResponse(baseResponse=param_error,
                                                       data="当app类型为得分类时，resultScoreRange必须填写！")


class updateScoringResult(Schema):
    id = fields.Int(
        required=True,
        allow_none=False,
        validate=validate.Range(min=1)
    )
    resultName = fields.Str(
        # 更新时，名字可以为空
        required=True,
        allow_none=True,
        validate=validate.Length(max=80, error="结果名称不得超过80个字符")
    )
    resultDesc = fields.Str(
        required=True,
        allow_none=True,
        validate=validate.Length(max=80, error="结果描述不得超过80个字符")
    )
    resultPicture = fields.URL(

        require_tld=True,  # 要求顶级域名（如 .com/.org）
        relative=False,  # 禁止相对URL（如 /path/to/resource）
        schemes={'http', 'https', 'ftp'}  # 允许的协议
    )
    resultProp = fields.List(
        required=True,
        allow_none=False,
        cls_or_instance=fields.String(),
        validate=validate.Length(min=1, error="选项数组至少需要包含一个元素")
    )
    resultScoreRange = fields.Int(
        required=True,
        allow_none=True,
    )

    def validate_id(self, data, **kwargs):
        scoring_result = ScoringResult.query.get(data.get('id'))
        if scoring_result is None:
            print("当前评分标准不存在，无法更新！")
            return ApiResponse.error_from_baseResponse(
                baseResponse=param_error,
                data="请重新检查要更新的评分标准！"
            )
        # TODO:在更新评分标准的时候，是否除id字段必须填写外，还有其他字段必填???或某些字段必不可填由于app_type的限制
        # TODO:比如：当app类型为测评类时，result_prop必须填写！
        # TODO:或者比如：当app类型为测评类时，resultScoreRange必须不填写！
        # TODO:认为：不管是否填写，全盘接受，通过app_type限制访问指定的字段:resultScoreRange,resultProp

class queryScoringResult(Schema):
    # 题目ID
    id = fields.Int(
        allow_none=True,
        required=False,
        validate=validate.Range(min=1, error="ID非法")
    )
    # 不需要的ID
    notId = fields.Int(
        allow_none=True,
        required=False,
        validate=validate.Range(min=1, error="ID非法")
    )
    # 必有值的数据
    pageSize = fields.Int(
        allow_none=True,
        validate=validate.Range(min=1)
    )
    current = fields.Int(
        allow_none=True,
        validate=validate.Range(min=1)
    )
    sortField = fields.Str(
        allow_none=True,
    )
    sortOrder = fields.Str(
        allow_none=True,
    )
    isDelete = fields.Int(
        required=True,
        allow_none=True,
        validate=validate.OneOf(
            [0,1],
            error="isDelete数值非法！"
        )
    )

    appId = fields.Int(
        allow_none=True,
    )
    userId = fields.Int(
        allow_none=True,
    )
    resultName = fields.Str(
        allow_none=True,
        validate=validate.Length(max=80, error="结果名称不得超过80个字符")
    )
    resultDesc = fields.Str(
        allow_none=True,
        validate=validate.Length(max=80, error="结果描述不得超过80个字符")
    )
    resultProp = fields.Str(
        allow_none=True,
        validate=validate.Length(min=1,error="结果prop长度最小为1")
    )
    resultScoreRange = fields.Int(
        allow_none=True,
    )
    def validate_appId(self,data,**kwargs):
        try:
            appId = int(data.get('appId'))
        except ValueError as err:
            print(f"appId有误:{err}")
            return ApiResponse.error_from_baseResponse(
                baseResponse=param_error,
                data="appId非法，应输入整数！"
            )
        app = App.query.get(appId)
        if app is None:
            print("评判策略对应的app不存在")
            return ApiResponse.error_from_baseResponse(
                baseResponse=param_error,
                data="请重新检查选择的app"
            )

    @pre_load
    def replace_none_with_default(self, data, **kwargs):
        not_none_fields_with_default = {
            'pageSize': 10,
            'current': 1,
            'sortField': 'id',
            'sortOrder': 'asc',
            'isDelete': None,
        }
        for field, default_value in not_none_fields_with_default.items():
            if data.get(field) is None:
                data[field] = default_value
            return data